//
//  Runtime.m
//  Charles
//
//  Created by Leo on 2017/6/20.
//  Copyright © 2017年 charles. All rights reserved.
//

#import "Runtime.h"
#import <objc/runtime.h>
@implementation Runtime

+ (void)test:(NSString *)key {
    //关联对象
    NSMutableDictionary <NSString *,NSNumber *> *dict = objc_getAssociatedObject(self, _cmd);
    NSLog(@"dict is %@",dict.description);
    if (!dict) {
        dict = @{}.mutableCopy;
        objc_setAssociatedObject(self, _cmd, dict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    NSLog(@"dict is %@",dict.description);
    NSNumber *number = dict[key];
    if (!number) {
        number = [NSNumber numberWithInt:1001];
        dict[key] = number;
    }
    NSLog(@"dict is %@",dict.description);
}

+ (void)testMethod {
    
    /*
     这句代码执行后，会从NSObject 的元类中查找foo 方法的实现，但是找不到，继续在元类的super class 中查找，由于NSObject的元类的super class 就是NSObject 本身，于是又回到NSObject的类对象中查找foo 方法，于是就找到了foo 方法。
     */
    [NSObject foo];
    [[NSObject new] foo];
    
    // 获取到类对象
    id cls = [Sark class];
    // 获取到类对象的首地址
    void *obj = &cls;
    [(__bridge id)obj speak];
    
    /*
     A: isKindOfClass:class 和 B: isMemberOfClass:class 的区别
     A：调用该方法的对象所属类，继承链中包含传入的class则返回Yes
     B：调用该方法的对象所属的类，必须是传入的class则返回Yes
     */
    
    BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
    BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
    BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];
    BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];
    
    
    bool res5 = [NSObject isKindOfClass:[NSObject class]];

    NSLog(@" --- %d %d %d %d %d",res1,res2,res3,res4,res5);
}

+ (void)testClassMethodWithOutImplementation {
    // 调用一个类的类方法fly，该方法在当前类中没有具体实现。但是在根类对象里面实现了同名的实例方法fly;
    // 此时会调用到根类对象的实例方法fly。
    // 原因：因为类方法存储在元类对象中， 逐级父类查找最终会找到根类（NSObject）对象实现的同名方法。
    [Sark fly];
}

@end

@implementation NSObject (Sark)

- (void)foo {
    NSLog(@"IMP: -[NSObject (Sark) foo]");
}

- (void)fly {
    NSLog(@"调用实例方法fly!!");
}

@end

@implementation Sark

- (void)speak {
    NSLog(@"my name is charles");
}

@end




